<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!-- 
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License. 
-->
<html>
<head>
    <link type="text/css" rel="stylesheet" href="https://struts.apache.org/css/default.css">
    <style type="text/css">
        .dp-highlighter {
            width:95% !important;
        }
    </style>
    <style type="text/css">
        .footer {
            background-image:      url('https://cwiki.apache.org/confluence/images/border/border_bottom.gif');
            background-repeat:     repeat-x;
            background-position:   left top;
            padding-top:           4px;
            color:                 #666;
        }
    </style>
    <link href='https://struts.apache.org/highlighter/style/shCoreStruts.css' rel='stylesheet' type='text/css' />
    <link href='https://struts.apache.org/highlighter/style/shThemeStruts.css' rel='stylesheet' type='text/css' />
    <script src='https://struts.apache.org/highlighter/js/shCore.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushPlain.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushXml.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushJava.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushJScript.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushGroovy.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushBash.js' type='text/javascript'></script>
    <script type="text/javascript">
        SyntaxHighlighter.defaults['toolbar'] = false;
        SyntaxHighlighter.all();
    </script>
    <script type="text/javascript" language="javascript">
        var hide = null;
        var show = null;
        var children = null;

        function init() {
            /* Search form initialization */
            var form = document.forms['search'];
            if (form != null) {
                form.elements['domains'].value = location.hostname;
                form.elements['sitesearch'].value = location.hostname;
            }

            /* Children initialization */
            hide = document.getElementById('hide');
            show = document.getElementById('show');
            children = document.all != null ?
                    document.all['children'] :
                    document.getElementById('children');
            if (children != null) {
                children.style.display = 'none';
                show.style.display = 'inline';
                hide.style.display = 'none';
            }
        }

        function showChildren() {
            children.style.display = 'block';
            show.style.display = 'none';
            hide.style.display = 'inline';
        }

        function hideChildren() {
            children.style.display = 'none';
            show.style.display = 'inline';
            hide.style.display = 'none';
        }
    </script>
    <title>Google App Engine (GAE)</title>
</head>
<body onload="init()">
<table border="0" cellpadding="2" cellspacing="0" width="100%">
    <tr class="topBar">
        <td align="left" valign="middle" class="topBarDiv" align="left" nowrap>
            &nbsp;<a href="home.html">Home</a>&nbsp;&gt;&nbsp;<a href="faqs.html">FAQs</a>&nbsp;&gt;&nbsp;<a href="google-app-engine-gae.html">Google App Engine (GAE)</a>
        </td>
        <td align="right" valign="middle" nowrap>
            <form name="search" action="https://www.google.com/search" method="get">
                <input type="hidden" name="ie" value="UTF-8" />
                <input type="hidden" name="oe" value="UTF-8" />
                <input type="hidden" name="domains" value="" />
                <input type="hidden" name="sitesearch" value="" />
                <input type="text" name="q" maxlength="255" value="" />
                <input type="submit" name="btnG" value="Google Search" />
            </form>
        </td>
    </tr>
</table>

<div id="PageContent">
    <div class="pageheader" style="padding: 6px 0px 0px 0px;">
        <!-- We'll enable this once we figure out how to access (and save) the logo resource -->
        <!--img src="/wiki/images/confluence_logo.gif" style="float: left; margin: 4px 4px 4px 10px;" border="0"-->
        <div style="margin: 0px 10px 0px 10px" class="smalltext">Apache Struts 2 Documentation</div>
        <div style="margin: 0px 10px 8px 10px"  class="pagetitle">Google App Engine (GAE)</div>

        <div class="greynavbar" align="right" style="padding: 2px 10px; margin: 0px;">
            <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=114612">
                <img src="https://cwiki.apache.org/confluence/images/icons/notep_16.gif"
                     height="16" width="16" border="0" align="absmiddle" title="Edit Page"></a>
            <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=114612">Edit Page</a>
            &nbsp;
            <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">
                <img src="https://cwiki.apache.org/confluence/images/icons/browse_space.gif"
                     height="16" width="16" border="0" align="absmiddle" title="Browse Space"></a>
            <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">Browse Space</a>
            &nbsp;
            <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=114612">
                <img src="https://cwiki.apache.org/confluence/images/icons/add_page_16.gif"
                     height="16" width="16" border="0" align="absmiddle" title="Add Page"></a>
            <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=114612">Add Page</a>
            &nbsp;
            <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=114612">
                <img src="https://cwiki.apache.org/confluence/images/icons/add_blogentry_16.gif"
                     height="16" width="16" border="0" align="absmiddle" title="Add News"></a>
            <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=114612">Add News</a>
        </div>
    </div>

    <div class="pagecontent">
        <div class="wiki-content">
            <div id="ConfluenceContent"><p>It is possible to run, at least, a simple Struts 2 application on GAE with a little work.  Namely, you need to tell OGNL to not do security manager permission checks, which will fail since GAE has a security manager and you don't have the ability to add the OGNL-specific permissions.  Therefore, somewhere in your initialization code, add this:</p>

<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">
OgnlRuntime.setSecurityManager(null);
</pre>
</div></div>

<p>The easiest place for this is in a Servlet context listener, executing when the context is initialized.</p>

<p>For Struts 2.1.8, Jeromy Evans did some work to get things running on GAE. The following post on the mailing list reports both the issues and the workarounds.</p>

<h3 id="GoogleAppEngine(GAE)-IssueswhendeployingonGAE">Issues when deploying on GAE</h3>

<p>Jeromy Evans: I've put in some more effort to get Struts 2.1.8 snapshot running in live GAE environment.  I made progress moving to Sitemesh 2.4.2, disabling OgnlRuntime SecurityManager and moving to convention-2.1.8-SNAPSHOT (WW-3114)</p>

<p>The next issue is that XWorks XMLConfigurationProvider throws a SecurityException on the following line (211):</p>

<p>// Force loading of class to detect no class def found exceptions<br clear="none">
cimpl.getDeclaredConstructors();</p>

<p>SecurityException: Unable to get members for o.a.s.c.PackageBasedActionConfigBuilder</p>

<p>cimpl is the Class of the ActionConfigBuilder bean specified in struts-plugin.xml and loaded by ClassLoaderTools.  I believe this is a technique to eagerly load the class.</p>

<p>I'm not sure why that's access is not permitted in the sandbox. It's not documented anywhere I can see and It only occurs in the live environment.</p>

<p>As a work-around (guess), I changed it to cimpl.getDeclaredClasses() instead which is permitted (I don't know if this has the same effect on the ClassLoader).  That got me past the issue above, but the same SecurityException occurs in XWork's ContainerImpl$ConstructorInjector.findConstructorIn():<br clear="none">
SecurityException: Unable to get members for Class o.a.s.v.v.VelocityManager</p>

<p>which seems to be a fundamental problem with XWork's constructor injection in GAE.</p>

<p>As a side note,  Guice 2's constructor injection works okay in GAE. I imagine the Guice 2 codebase is now very different beast than XWork's IOC though.</p>

<p>I guess I need to approach the GAE forum now.  Has anyone got any ideas about what to attempt next on the S2/Xwork side?  Stack traces for the two cases are below.</p>

<div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
<pre> 
Failed startup of context com.google.apphosting.utils.jetty.RuntimeAppEngineWebAppContext@67fe80{/,/base/data/home/apps/{appname}/1.335834217966711427}
Unable to load configuration. - bean - jar:file:/base/data/home/apps/{appname}/1.335834217966711427/WEB-INF/lib/struts2-convention-plugin-2.1.8-SNAPSHOT.jar!/struts-plugin.xml:32:155
       at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:431)
       at org.apache.struts2.dispatcher.ng.InitOperations.initDispatcher(InitOperations.java:69)
       at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter.init(StrutsPrepareFilter.java:50)
       at com.google.inject.servlet.FilterDefinition.init(FilterDefinition.java:81)
       at com.google.inject.servlet.ManagedFilterPipeline.initPipeline(ManagedFilterPipeline.java:102)
       at com.google.inject.servlet.GuiceFilter.init(GuiceFilter.java:168)
       at org.mortbay.jetty.servlet.FilterHolder.doStart(FilterHolder.java:99)
       at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40)
       at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:589)
       at org.mortbay.jetty.servlet.Context.startContext(Context.java:139)
       at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1218)
       at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:500)
       at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:448)
       at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40)
       at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.createHandler(AppVersionHandlerMap.java:190)
       at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.getHandler(AppVersionHandlerMap.java:167)
       at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:127)
       at com.google.apphosting.runtime.JavaRuntime.handleRequest(JavaRuntime.java:235)
       at com.google.apphosting.base.RuntimePb$EvaluationRuntime$6.handleBlockingRequest(RuntimePb.java:4823)
       at com.google.apphosting.base.RuntimePb$EvaluationRuntime$6.handleBlockingRequest(RuntimePb.java:4821)
       at com.google.net.rpc.impl.BlockingApplicationHandler.handleRequest(BlockingApplicationHandler.java:24)
       at com.google.net.rpc.impl.RpcUtil.runRpcInApplication(RpcUtil.java:359)
       at com.google.net.rpc.impl.Server$2.run(Server.java:820)
       at com.google.tracing.LocalTraceSpanRunnable.run(LocalTraceSpanRunnable.java:56)
       at com.google.tracing.LocalTraceSpanBuilder.internalContinueSpan(LocalTraceSpanBuilder.java:516)
       at com.google.net.rpc.impl.Server.startRpc(Server.java:775)
       at com.google.net.rpc.impl.Server.processRequest(Server.java:348)
       at com.google.net.rpc.impl.ServerConnection.messageReceived(ServerConnection.java:436)
       at com.google.net.rpc.impl.RpcConnection.parseMessages(RpcConnection.java:319)
       at com.google.net.rpc.impl.RpcConnection.dataReceived(RpcConnection.java:290)
       at com.google.net.async.Connection.handleReadEvent(Connection.java:428)
       at com.google.net.async.EventDispatcher.processNetworkEvents(EventDispatcher.java:762)
       at com.google.net.async.EventDispatcher.internalLoop(EventDispatcher.java:207)
       at com.google.net.async.EventDispatcher.loop(EventDispatcher.java:101)
       at com.google.net.rpc.RpcService.runUntilServerShutdown(RpcService.java:251)
       at com.google.apphosting.runtime.JavaRuntime$RpcRunnable.run(JavaRuntime.java:374)
       at java.lang.Thread.run(Unknown Source)
Caused by: Unable to load configuration. - bean - jar:file:/base/data/home/apps/{appname}/1.335834217966711427/WEB-INF/lib/struts2-convention-plugin-2.1.8-SNAPSHOT.jar!/struts-plugin.xml:32:155
       at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:58)
       at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:374)
       at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:418)
       ... 36 more
Caused by: Unable to load bean: type:org.apache.struts2.convention.ActionConfigBuilder class:org.apache.struts2.convention.PackageBasedActionConfigBuilder - bean - jar:file:/base/data/home/apps/{appname}/1.335834217966711427/WEB-INF/lib/struts2-convention-plugin-2.1.8-SNAPSHOT.jar!/struts-plugin.xml:32:155
       at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.register(XmlConfigurationProvider.java:222)
       at org.apache.struts2.config.StrutsXmlConfigurationProvider.register(StrutsXmlConfigurationProvider.java:101)
       at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:165)
       at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:55)
       ... 38 more
Caused by: java.lang.SecurityException: Unable to get members for class org.apache.struts2.convention.PackageBasedActionConfigBuilder
       at com.google.apphosting.runtime.security.shared.intercept.java.lang.Class_$10.run(Class_.java:357)
       at com.google.apphosting.runtime.security.shared.intercept.java.lang.Class_$10.run(Class_.java:347)
       at java.security.AccessController.doPrivileged(Native Method)
       at com.google.apphosting.runtime.security.shared.intercept.java.lang.Class_.getMembers(Class_.java:347)
       at com.google.apphosting.runtime.security.shared.intercept.java.lang.Class_.getDeclaredConstructors(Class_.java:192)
       at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.register(XmlConfigurationProvider.java:212)
       ... 41 more
</pre>
</div></div> 

<p>&#8212; case two &#8212;</p>
<div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
<pre> 
{
[{appname}/1.335835094531171610].&lt;stdout&gt;: 642  [Runtime Network Thread] ERROR org.apache.struts2.dispatcher.Dispatcher  - Dispatcher initialization failed
java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.SecurityException: Unable to get members for class org.apache.struts2.views.velocity.VelocityManager
       at com.opensymphony.xwork2.inject.ContainerImpl$MethodInjector.inject(ContainerImpl.java:295)
       at com.opensymphony.xwork2.inject.ContainerImpl$2.call(ContainerImpl.java:104)
       at com.opensymphony.xwork2.inject.ContainerImpl$2.call(ContainerImpl.java:102)
       at com.opensymphony.xwork2.inject.ContainerImpl.callInContext(ContainerImpl.java:574)
       at com.opensymphony.xwork2.inject.ContainerImpl.injectStatics(ContainerImpl.java:101)
       at com.opensymphony.xwork2.inject.ContainerBuilder.create(ContainerBuilder.java:493)
       at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:184)
       at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:55)
       at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:374)
       at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:418)
       at org.apache.struts2.dispatcher.ng.InitOperations.initDispatcher(InitOperations.java:69)
       at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter.init(StrutsPrepareFilter.java:50)
       at com.google.inject.servlet.FilterDefinition.init(FilterDefinition.java:81)
       at com.google.inject.servlet.ManagedFilterPipeline.initPipeline(ManagedFilterPipeline.java:102)
       at com.google.inject.servlet.GuiceFilter.init(GuiceFilter.java:168)
       at org.mortbay.jetty.servlet.FilterHolder.doStart(FilterHolder.java:99)
       at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40)
       at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:589)
       at org.mortbay.jetty.servlet.Context.startContext(Context.java:139)
       at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1218)
       at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:500)
       at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:448)
       at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40)
       at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.createHandler(AppVersionHandlerMap.java:190)
       at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.getHandler(AppVersionHandlerMap.java:167)
       at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:127)
       at com.google.apphosting.runtime.JavaRuntime.handleRequest(JavaRuntime.java:235)
       at com.google.apphosting.base.RuntimePb$EvaluationRuntime$6.handleBlockingRequest(RuntimePb.java:4823)
       at com.google.apphosting.base.RuntimePb$EvaluationRuntime$6.handleBlockingRequest(RuntimePb.java:4821)
       at com.google.net.rpc.impl.BlockingApplicationHandler.handleRequest(BlockingApplicationHandler.java:24)
       at com.google.net.rpc.impl.RpcUtil.runRpcInApplication(RpcUtil.java:359)
       at com.google.net.rpc.impl.Server$2.run(Server.java:820)
       at com.google.tracing.LocalTraceSpanRunnable.run(LocalTraceSpanRunnable.java:56)
       at com.google.tracing.LocalTraceSpanBuilder.internalContinueSpan(LocalTraceSpanBuilder.java:516)
       at com.google.net.rpc.impl.Server.startRpc(Server.java:775)
       at com.google.net.rpc.impl.Server.processRequest(Server.java:348)
       at com.google.net.rpc.impl.ServerConnection.messageReceived(ServerConnection.java:436)
       at com.google.net.rpc.impl.RpcConnection.parseMessages(RpcConnection.java:319)
       at com.google.net.rpc.impl.RpcConnection.dataReceived(RpcConnection.java:290)
       at com.google.net.async.Connection.handleReadEvent(Connection.java:428)
       at com.google.net.async.EventDispatcher.processNetworkEvents(EventDispatcher.java:762)
       at com.google.net.async.EventDispatcher.internalLoop(EventDispatcher.java:207)
       at com.google.net.async.EventDispatcher.loop(EventDispatcher.java:101)
       at com.google.net.rpc.RpcService.runUntilServerShutdown(RpcService.java:251)
       at com.google.apphosting.runtime.JavaRuntime$RpcRunnable.run(JavaRuntime.java:374)
       at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.SecurityException: Unable to get members for class org.apache.struts2.views.velocity.VelocityManager
       at com.opensymphony.xwork2.inject.ContainerBuilder$4.create(ContainerBuilder.java:132)
       at com.opensymphony.xwork2.inject.Scope$2$1.create(Scope.java:51)
       at com.opensymphony.xwork2.inject.ContainerImpl$ParameterInjector.inject(ContainerImpl.java:462)
       at com.opensymphony.xwork2.inject.ContainerImpl.getParameters(ContainerImpl.java:477)
       at com.opensymphony.xwork2.inject.ContainerImpl.access$000(ContainerImpl.java:34)
       at com.opensymphony.xwork2.inject.ContainerImpl$MethodInjector.inject(ContainerImpl.java:293)
       ... 45 more
Caused by: java.lang.RuntimeException: java.lang.SecurityException: Unable to get members for class org.apache.struts2.views.velocity.VelocityManager
       at com.opensymphony.xwork2.inject.ContainerImpl.inject(ContainerImpl.java:495)
       at com.opensymphony.xwork2.inject.ContainerImpl$7.call(ContainerImpl.java:532)
       at com.opensymphony.xwork2.inject.ContainerImpl.callInContext(ContainerImpl.java:581)
       at com.opensymphony.xwork2.inject.ContainerImpl.inject(ContainerImpl.java:530)
       at com.opensymphony.xwork2.config.impl.LocatableFactory.create(LocatableFactory.java:32)
       at com.opensymphony.xwork2.inject.ContainerBuilder$4.create(ContainerBuilder.java:130)
       ... 50 more
Caused by: java.lang.SecurityException: Unable to get members for class org.apache.struts2.views.velocity.VelocityManager
       at com.google.apphosting.runtime.security.shared.intercept.java.lang.Class_$10.run(Class_.java:357)
       at com.google.apphosting.runtime.security.shared.intercept.java.lang.Class_$10.run(Class_.java:347)
       at java.security.AccessController.doPrivileged(Native Method)
       at com.google.apphosting.runtime.security.shared.intercept.java.lang.Class_.getMembers(Class_.java:347)
       at com.google.apphosting.runtime.security.shared.intercept.java.lang.Class_.getDeclaredConstructors(Class_.java:192)
       at com.opensymphony.xwork2.inject.ContainerImpl$ConstructorInjector.findConstructorIn(ContainerImpl.java:366)
       at com.opensymphony.xwork2.inject.ContainerImpl$ConstructorInjector.&lt;init&gt;(ContainerImpl.java:319)
       at com.opensymphony.xwork2.inject.ContainerImpl$5.create(ContainerImpl.java:305)
       at com.opensymphony.xwork2.inject.ContainerImpl$5.create(ContainerImpl.java:304)
       at com.opensymphony.xwork2.inject.util.ReferenceCache$CallableCreate.call(ReferenceCache.java:150)
       at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
       at java.util.concurrent.FutureTask.run(Unknown Source)
       at com.opensymphony.xwork2.inject.util.ReferenceCache.internalCreate(ReferenceCache.java:76)
       at com.opensymphony.xwork2.inject.util.ReferenceCache.get(ReferenceCache.java:116)
       at com.opensymphony.xwork2.inject.ContainerImpl.getConstructor(ContainerImpl.java:594)
       at com.opensymphony.xwork2.inject.ContainerImpl.inject(ContainerImpl.java:491)
       ... 55 more
</pre>
</div></div> 

<h3 id="GoogleAppEngine(GAE)-Workarounds">Workarounds</h3>

<blockquote><p>As a work-around (guess), I changed it to cimpl.getDeclaredClasses() instead which is permitted (I don't know if this has the same effect on the ClassLoader).  That got me past the issue above, but the same SecurityException occurs in XWork's ContainerImpl$ConstructorInjector.findConstructorIn():</p></blockquote>
<p>    SecurityException: Unable to get members for Class o.a.s.v.v.VelocityManager</p>


<p>This exception occurs within Google App Engine because XWork eagerly loads the VelocityManager Class for the bean struts-default.xml.  VelocityManager uses the VelocityToolbox optional dependency (in velocity-tools) which is not deployed with the application by default.  I presume the GAE ClassLoader checks all imported classes against the whitelist and fails if the class is not found.<br clear="none">
It's overcome by deploying the application velocity.</p>

<p>I now have Struts 2.1.8-snapshot with Convention, Sitemesh and JSON, within a Guice2 servlet filter for IOC, running within GAE.</p>

<p>The mandatory work-around are:</p>
<ul class="alternate"><li>to still use a ServletContextListener to disable the OgnlRuntime security manager.  If not done, an IllegalAccessException occurs in OgnlUtil.setProperty(String) at run-time.  This exception is swallowed, but it typically results in an NPE in ServletRedirectResult.isPathUrl(String) because location cannot be set.</li><li>the velocity dependencies need to be deployed with the application even if not in use.  If not done, a security exception occurs while getting the members of VelocityManager because VelocityManager imports VelocityToolbox and VelocityEngine.</li></ul>


<p>I don't think any S2 code changes are required at this time.</p></div>
        </div>

        
    </div>
</div>
<div class="footer">
    Generated by CXF SiteExporter
</div>
</body>
</html>
